<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="Permissions-Policy" content="camera=(self)">

	<title>WebRTC</title>
</head>
<link rel="stylesheet" href="./css/commer.css?v=4">
<script src="./js/uni.webview.1.5.6.js"></script>
<script src="./js/vue@2.js"></script>
<!-- <script src="./js/vconsole.min.js"></script> -->

<body>
	<div id="app" :class="{appShow:appShow}">
		<div class="formattedTime" v-show="status == 3">{{ formattedTime }}</div>
		<div class="smallVideo zIndex" v-show="status == 3 && call_type==2" @click="isbigVideo = !isbigVideo"></div>
		<video poster="./img/voiceBg.jpg" playsinline autoplay id="localVideo" v-show="isCameraOn && call_type==2"
			:class="isbigVideo?'bigVideo':'smallVideo'" autoplay muted></video>
		<video poster="./img/smallBg.jpg" playsinline autoplay id="remoteVideo"
			v-show="status == 3 && isremoteVideoCameraOn && call_type==2" :class="isbigVideo?'smallVideo':'bigVideo'"
			autoplay></video>
		<div class="noVideoBg" v-show="status == 3 && call_type==2">
			<img v-show="isbigVideo"
				:src="(friendInfo.picture && friendInfo.picture != 'null') ? friendInfo.picture : './img/head.jpg'"
				alt="">
			<img v-show="!isbigVideo"
				:src="(myUserInfo.picture && myUserInfo.picture != 'null') ? myUserInfo.picture : './img/head.jpg'"
				alt="">
		</div>

		<div class="friendInfoCla"
			v-show="status != 3 || (isremoteVideoCameraOn == false && isbigVideo == false) || call_type==1">

			<div><img
					:src="(friendInfo.picture && friendInfo.picture != 'null') ? friendInfo.picture : './img/head.jpg'"
					alt=""></div>
			<div>{{ friendInfo.user_name }}</div>
		</div>

		<div class="handleOfferBtn">
			<div class="tips">
				<span v-if="status == 1">等待对方接受邀请</span>
				<span v-if="status == 2">邀请你接受语音通话</span>
			</div>
			<div class="videoBtn">
				<!-- 切换摄像头 -->
				<div v-if="call_type==2">
					<img @click="switchCamera" src="./img/flip.png" alt="">
					<p>翻转</p>
				</div>
				<div @click="toggleMicrophone">
					<img :src="isMicrophoneOn ? './img/openMicrophone.png' : './img/closeMicrophone.png'" alt="麦克风状态">
					<p>{{isMicrophoneOn?'麦克风已开':'麦克风已关'}}</p>
				</div>
				<div v-if="call_type==2" @click="toggleCamera">
					<img :src="isCameraOn ? './img/openCamera.png' : './img/closeCamera.png'" alt="麦克风状态">
					<p>{{isCameraOn?'摄像头已开':'摄像头已关'}}</p>
				</div>


			</div>

			<div class="hangUpAnswer">
				<!-- 挂断 -->
				<img @click="hangUp" src="./img/hangUp.png" alt="">
				<!-- 同意 -->
				<img @click="handleOfferFn" v-if="status == 2"
					:src="callStatus ? './img/loading.gif' : './img/answer.png'">
			</div>
		</div>
	</div>
</body>

<script>
	// var vConsole = new VConsole();
	let isH5 = true
	let localStream;
	let audioTrack;
	let currentDeviceId = null;
	let isSwitching = false; // 用于防止过快点击
	let switchingTimeout = null; // 用于记录流切换的延时
	let sendIceArr = [];
	var faqifang = false; //是否发起方
	// 获取路径上的参数
	function getQueryParams() {
		var queryString = location.search;
		var queryParams = {};
		if (queryString.indexOf('?') === 0) {
			queryString = queryString.substring(1);
		}
		var pairs = queryString.split('&');
		for (var i = 0; i < pairs.length; i++) {
			var pair = pairs[i].split('=');
			var key = decodeURIComponent(pair[0]);
			var value = decodeURIComponent(pair[1]);
			queryParams[key] = value;
		}
		return queryParams;
	}

	let getQueryParamsObj = getQueryParams()
	let WebRtcConfig2 = JSON.parse(getQueryParamsObj.WebRtcConfig)
	let iceServers = [{
		urls: WebRtcConfig2.stun // Google STUN 服务器
	}]
	
	if (WebRtcConfig2.turn) {
		iceServers.push(WebRtcConfig2.turn)
	}
	const configuration = {
		iceServers,
		iceTransportPolicy: "all", // 使用所有可用的传输方式
		bundlePolicy: "max-bundle", // 将多个流合并到一个连接
		rtcpMuxPolicy: "require" // 强制使用 RTCPMUX
	};
	
	console.log(configuration)
	let peerConnection = new RTCPeerConnection(configuration);
	document.addEventListener('UniAppJSBridgeReady', function () {
		uni.getEnv(function (res) {
			if (res.h5) {
				isH5 = true;
			} else {
				isH5 = false;
			}

			new Vue({
				el: '#app',

				data: {
					callStatus: false,
					callDuration: 0, // 通话时长（秒）
					timer: null, // 定时器引用
					callTimer: null,
					callTimer2: null,
					appShow: false,
					friendInfo: {},
					myUserInfo: {},
					formCallData: {},
					callOffer: {},
					status: '',
					call_type: 1,
					isbigVideo: true,
					isMicrophoneOn: true, //麦克风
					isCameraOn: true, //摄像头
					isremoteVideoCameraOn: true, //远端摄像头
					isCaller: '', //是否是拨打方
					isLoading: false,
					offerParts: [],
					totalParts: 5,// 数据的总部分数
					loadedParts: 0,// 已加载的部分数




				},
				computed: {

					// 格式化时间为 00:00
					formattedTime() {
						const minutes = String(Math.floor(this.callDuration / 60)).padStart(2,
							'0');
						const seconds = String(this.callDuration % 60).padStart(2, '0');
						return `${minutes}:${seconds}`;
					},
				},

				mounted() {
					// webview界面加载完
					this.postMessageFn({
						type: "interfaceLoaded"
					})

					let callData = {}
					if (getQueryParamsObj.callData) {
						callData = JSON.parse(getQueryParamsObj.callData);
						this.callData = callData

					} else if (getQueryParamsObj.formCallData) {
						callData = JSON.parse(getQueryParamsObj.formCallData);
						this.formCallData = callData
					}

					this.call_type = callData.call_type
					this.friendInfo = callData.friendInfo
					this.myUserInfo = callData.myUserInfo

					this.RTCPeerConnectionFn().then(() => {

						this.addEventListenerFn()
						if (getQueryParamsObj.callData) {
							// 拨打电话
							console.log('拨打电话', this.callData)
							this.status = 1
							this.isCaller = 1 //设置自己为拨打方
							this.isbigVideo = true
							this.isLoading = true

							let content = {
								call_type: this.call_type,
								type: 3 //判断对方是否在线
							}
							var sendData = {
								type: 'push',
								content: JSON.stringify(content)
							};
							// 发送信息询问对方是否在线
							this.postMessageFn(sendData)
							console.log('你在线吗？1')
							if (this.callTimer) {
								clearInterval(this.callTimer);
							}
							this.callTimer = setInterval(() => {
								console.log('你在线吗？2')
								this.postMessageFn(sendData)
							}, 3000);
							// 一分钟自动挂断
							this.callTimer2 = setTimeout(() => {
								console.log('一分钟自动挂断')
								if (this.callTimer) {
									clearInterval(this.callTimer);
									this.hangUp()
									this.isCaller = 2 //对方未接听
								}
							}, 60 * 1000)



						}
						// 来电话
						if (getQueryParamsObj.formCallData) {
							// 告诉对方 我在线
							console.log('来电话,告诉对方 我在线', this.formCallData)
							this.postMessageFn({
								type: "push",
								content: JSON.stringify({
									type: 4,
								}),
							})
							this.status = 2
							this.isbigVideo = true
						}
					}).catch(error => {
						console.error('RTCPeerConnection 初始化失败', error);
					});

				},
				beforeDestroy() {
					// 组件销毁时清除定时器
					if (this.timer) {
						clearInterval(this.timer);
					}
					if (this.callTimer) {
						clearInterval(this.callTimer)
					}
					if (this.callTimer2) {
						clearTimeout(this.callTimer2)
					}


					window.removeEventListener('storage', this.addEventListenerFn);
				},
				methods: {


					// 监听缓存中的数据变化
					addEventListenerFn() {
						window.addEventListener('storage', async (e) => {
							console.log('监听缓存中的数据变化', e)

							// 检查是哪个部分的缓存被更新
							if (e.key && e.key.startsWith('_offer')) {
								// 提取部分数字
								const partIndex = parseInt(e.key.replace('_offer', ''), 10);

								// 如果该部分数据为空，则跳过
								if (!e.newValue) {
									console.log(`offer${partIndex} 数据为空，跳过处理`);
									return;
								}

								// 存储该部分数据
								this.offerParts[partIndex] = e.newValue; // 使用新值来更新数组中的部分

								// 增加已加载部分计数
								this.loadedParts++;

								console.log(`当前已加载 ${this.loadedParts} 个部分`);

								// 如果所有部分都加载完成
								if (this.loadedParts === this.totalParts) {
									// 合并所有部分
									const fullOffer = this.offerParts.join('');

									// 解码并解析原始对象
									const originalOffer = JSON.parse(decodeURIComponent(fullOffer));
									console.log('完整的 callOffer 数据:', originalOffer);
									this.callOffer = originalOffer
									console.log('对方call过来的数据----', this.callOffer)
									this.isLoading = true

									// 可以在这里做进一步的操作，例如：更新界面等

									// 清除缓存中的数据
									for (let i = 0; i < this.totalParts; i++) {
										localStorage.removeItem(`_offer${i}`);
									}

									// 清除已加载的部分和计数
									this.offerParts = [];
									this.loadedParts = 0;
								}
							}


							// 对方通过电话
							if (e.key === 'callConnected') {
								let callConnected = JSON.parse(localStorage.getItem(
									'callConnected'));
								console.log('通过电话', callConnected)
								this.status = 3
								this.isbigVideo = false
								this.call_type = callConnected.call_type
								this.friendInfo = callConnected.friendInfo
								this.myUserInfo = callConnected.myUserInfo
								console.log('通过电话', callConnected.Content)
								await peerConnection.setRemoteDescription(
									new RTCSessionDescription(callConnected
										.Content.answer));
								sendIceArr.forEach((item, idx) => {
									console.log('发送sendIceArr' + idx, item)
									this.postMessageFn(item)
								})
								this.startCall()
							}

							// 发送handleICECandidate
							if (e.key === 'handleICECandidate') {
								let content = JSON.parse(localStorage.getItem(
									'handleICECandidate'));
								content.iceCandidateArr.forEach((item) => {
									console.log('发送handleICECandidate', item
										.candidate)
									this.handleICECandidate(item.candidate)

								})

							}


							// 自定义消息
							if (e.key === 'customMessage') {
								let content = JSON.parse(localStorage.getItem(
									'customMessage'));
								console.log('自定义消息来了', content)
								// 关闭开启摄像头
								if (content.content.type == 1) {
									this.isremoteVideoCameraOn = content.content
										.isCameraOn
								}
								// 对方退出通话
								if (content.content.type == 2) {
									if (content.content.formattedTime) {
										this.endCall()
										this.formattedTime = content.content
											.formattedTime
									}
									this.hangUp()
								}

								// type: 3//判断对方是否在线
								// type: 6//忙线中

								// 对方在线
								if (content.content.type == 4) {
									console.log('对方有在线，我call数据过去')
									if (this.callTimer) {
										clearInterval(this.callTimer);
									}
									this.CallFn(this.callData.call_type)



								}

								// 挂断电话
								if (content.content.type == 5) {

									this.hangUp()
								}





							}
						});
					},
					// 创建 SDP offer
					async createOffer() {
						try {
							const offer = await peerConnection.createOffer();
							await peerConnection.setLocalDescription(offer);
							return offer;
						} catch (error) {
							console.error('Error creating offer: ', error);
						}
						return null;
					},
					// 拨打电话
					async CallFn(call_type) {
						var offer = await this.createOffer();
						if (offer == null) {
							console.log('创建 Offer 失败')
							return;
						}
						var obj = {
							cmd: "webrtc",
							user_id: this.friendInfo.id,
							type: 'offer',
							call_type: call_type,
							offer: JSON.stringify(peerConnection.localDescription)
						};
						this.postMessageFn(obj)
						sendIceArr = []; //ICE包置为空
						faqifang = true;
					},

					// 接听电话
					async handleOfferFn(type) {
						console.log('接听电话~')
						if (this.callStatus && !type) {
							return
						}
						console.log('this.isLoading', this.isLoading)
						this.callStatus = true
						if (this.isLoading) {
							let content = this.callOffer.Content
							console.log('接听电话content', content)

							await peerConnection.setRemoteDescription(
								new RTCSessionDescription(content.offer));
							const answer = await peerConnection.createAnswer();
							await peerConnection.setLocalDescription(answer);
							var obj = {
								cmd: "webrtc",
								user_id: this.friendInfo.id,
								call_type: content.call_type,
								type: 'answer',
								answer: JSON.stringify(answer)
							};
							this.postMessageFn(obj)

							setTimeout(() => {
								if (peerConnection.iceConnectionState === 'connected') {
									console.log('通话已连接')
									// 通话已连接
									this.status = 3
									this.isbigVideo = false
									this.postMessageFn({
										type: "connected"
									})
									this.startCall()
								} else {
									setTimeout(() => {
										this.handleOfferFn(1)
									}, 500)

									console.log('通话没链接11')

								}

							}, 500)




						} else {
							setTimeout(() => {
								this.handleOfferFn(1)
							}, 1000)
							console.log('通话没链接22')

						}

					},

					// 接收并设置远端的 ICE 候选
					handleICECandidate(candidate) {

						var wantHostMode = false;
						var wantReflexiveMode = false;
						var wantRelayMode = true; //此时此刻我们只想要后台中转模式
						var isHost = (candidate.candidate.indexOf('typ host') !== -1);
						var isSrflx = (candidate.candidate.indexOf('srflx') !== -1);
						var isRelay = (candidate.candidate.indexOf('relay') !== -1);
						var candidateType = isHost ? 'host' : (isSrflx ? 'srflx' : 'relay');

						//host（局域网直连）、srflx（打洞直连）、relay（服务器中转）
						if (wantHostMode && candidate.candidate.indexOf('typ host') == -1)
							return;

						if (wantReflexiveMode && candidate.candidate.indexOf('srflx') == -1)
							return;

						if (wantRelayMode && candidate.candidate.indexOf('relay') == -1)
							return;

						console.log("candidateType:" + candidateType);
						console.log('接收到 ICE 候选:', candidate.candidate);

						peerConnection.addIceCandidate(new RTCIceCandidate(candidate))
							.then(() => {
								// 这里是成功的回调
								console.log('成功添加 ICE 候选');
							})
							.catch(error => {
								// 这里是错误的回调
								console.error('添加 ICE 候选失败', error);
							});
					},


					// 结束通话，关闭连接和释放资源
					hangUp() {
						this.appShow = false

						this.endCall()
						try {
							// 停止本地媒体流
							if (localStream) {
								localStream.getTracks().forEach(track => track.stop());
								document.getElementById('localVideo').srcObject = null;
								localStream = null; // 清除引用
							}
							// 停止远程媒体流
							const remoteVideoDom = document.getElementById('remoteVideo');
							if (remoteVideoDom && remoteVideoDom.srcObject) {
								const remoteStream = remoteVideoDom.srcObject;
								remoteStream.getTracks().forEach(track => track.stop());
								remoteVideoDom.srcObject = null;
							}

							// 清理 peerConnection 相关事件
							if (peerConnection) {
								// 解除 ICE 候选和媒体流的监听
								peerConnection.onicecandidate = null;
								peerConnection.ontrack = null;

								// 关闭连接并释放资源
								peerConnection.close();
								peerConnection = null; // 置空引用
							}

						} catch (error) {

						}
						console.log('WebRTC 连接已关闭 this.callDuration--', this.callDuration);


						// 发送消息通知

						let obj = {
							type: "goBack",
							status: this.status
						}
						if (this.callDuration > 0) {

							obj.formattedTime = this.formattedTime
						}
						if (this.callDuration == 0 && this.isCaller == 2) {
							obj['message_type'] = 8
						}
						if (this.isCaller) {
							obj['clickType'] = this.isCaller
						}
						console.log('通话结束', obj)

						this.postMessageFn(obj);
					},

					// 初始化数据
					initializeCamera(deviceId = null, callback) {
						// 设置基础约束条件，仅包含音频部分
						let constraints = {
							audio: this.isMicrophoneOn // 保持当前麦克风的状态
						};

						// 如果 call_type 为 2，则添加摄像头的约束条件
						if (this.call_type == 2) {
							constraints['video'] = deviceId ? {
								deviceId: {
									exact: deviceId
								}
							} : true;
						}

						navigator.mediaDevices.getUserMedia(constraints)
							.then(stream => {
								console.log('摄像头', stream)
								// 处理视频相关逻辑，仅在 call_type === 2 时执行
								if (this.call_type == 2) {
									document.getElementById('localVideo').srcObject = stream;
									document.getElementById('localVideo').muted = true;

									// 获取当前摄像头设备 ID
									const videoTrack = stream.getVideoTracks()[0];
									const device = videoTrack.getSettings();
									currentDeviceId = device.deviceId;
								}

								// 将轨道添加到 peerConnection 中
								stream.getTracks().forEach(track => peerConnection.addTrack(
									track, stream));

								// 存储本地流
								localStream = stream;
								this.appShow = true



								// 调用回调函数，通知初始化完成
								if (callback) callback();
							})
							.catch(error => {
								alert('无法访问摄像头或麦克风')
								console.error('无法访问摄像头或麦克风', error);
							});
					},


					// 切换摄像头
					switchCamera() {
						// 防止频繁点击
						if (isSwitching) {
							console.log('摄像头切换操作正在进行中，请稍后...');
							return;
						}

						isSwitching = true; // 标记正在进行流切换

						// 获取当前的视频轨道
						const videoTrack = localStream.getVideoTracks()[0];

						// 停止当前的视频轨道，释放资源
						videoTrack.stop();

						// 获取设备列表
						navigator.mediaDevices.enumerateDevices().then(devices => {
							const videoDevices = devices.filter(device => device.kind ===
								'videoinput');

							if (videoDevices.length <= 1) {
								console.log('没有多个摄像头可供切换');
								isSwitching = false; // 重置标记
								return;
							}

							// 查找当前设备在设备列表中的位置
							const currentDeviceIndex = videoDevices.findIndex(device =>
								device.deviceId === videoTrack.getSettings().deviceId);
							const nextDeviceIndex = (currentDeviceIndex + 1) %
								videoDevices.length;
							const nextDeviceId = videoDevices[nextDeviceIndex].deviceId;

							console.log('切换到摄像头:', nextDeviceId);

							// 获取新的媒体流，保持麦克风的状态
							navigator.mediaDevices.getUserMedia({
								video: {
									deviceId: nextDeviceId
								},
								audio: this.isMicrophoneOn // 使用当前麦克风的状态
							})
								.then(stream => {
									// 更新本地视频显示
									document.getElementById('localVideo').srcObject =
										stream;
									document.getElementById('localVideo').muted =
										true;

									// 获取新的视频轨道和设备信息
									const videoTrack = stream.getVideoTracks()[0];
									const device = videoTrack.getSettings();
									currentDeviceId = device.deviceId;

									// 替换旧的视频轨道
									peerConnection.getSenders().forEach(sender => {
										if (sender.track && sender.track
											.kind === 'video') {
											sender.replaceTrack(videoTrack);
										}
									});

									// 确保音频轨道保持原有状态
									const audioTrack = stream.getAudioTracks()[0];
									if (audioTrack) {
										// 使用 isMicrophoneOn 确保麦克风开关状态
										audioTrack.enabled = this.isMicrophoneOn;
									} else {
										console.log('没有音频轨道');
									}

									// 更新本地流
									localStream = stream;

									// 延时重置防止频繁点击
									switchingTimeout = setTimeout(() => {
										isSwitching = false; // 切换完成，允许下次切换
									}, 1000); // 设置延迟1秒防止过快点击
								})
								.catch(error => {
									console.error('getUserMedia 失败:', error);
									if (error.name === 'NotFoundError') {
										console.error('没有找到合适的摄像头设备');
									} else if (error.name === 'NotAllowedError') {
										console.error('用户拒绝了权限请求');
									} else {
										console.error('其他错误', error);
									}
									isSwitching = false; // 发生错误时重置标记
								});
						})
							.catch(error => {
								console.error('获取设备列表失败', error);
								isSwitching = false; // 发生错误时重置标记
							});
					},
					// 切换麦克风的开启和关闭
					toggleMicrophone() {
						if (!localStream) {
							console.log('本地流未初始化');
							return;
						}

						console.log('localStream---', localStream.getAudioTracks());

						// 获取音频轨道
						const audioTrack = localStream.getAudioTracks()[0];

						// 判断音频轨道是否存在
						if (audioTrack) {
							// 切换音频轨道的 enabled 属性
							audioTrack.enabled = !audioTrack.enabled;
							this.isMicrophoneOn = audioTrack.enabled;

							// 根据麦克风的状态进行相应的处理
							if (audioTrack.enabled) {
								console.log('麦克风已开启');
							} else {
								console.log('麦克风已关闭');
							}

							// 更新远程音频流（通过设置 audioTrack.enabled 影响远程音频的接收）
							this.updateRemoteAudioTrackState(audioTrack.enabled);
						} else {
							console.log('未找到音频轨道');
							// 如果没有音频轨道，可以尝试重新初始化流
							this.reinitializeStream();
						}
					},

					// 重新初始化音频流
					reinitializeStream() {
						console.log('重新初始化音频流...');
						navigator.mediaDevices.getUserMedia({
							audio: true
						})
							.then(stream => {
								// 更新本地流
								localStream = stream;
								// 绑定音频轨道
								const audioTrack = localStream.getAudioTracks()[0];
								if (audioTrack) {
									// 将新的音频轨道的 enabled 属性设置为初始状态
									audioTrack.enabled = this.isMicrophoneOn;
									console.log('重新获取并启用音频轨道');
								}
							})
							.catch(error => {
								console.error('重新获取音频流失败', error);
							});
					},

					// 切换摄像头的开启和关闭
					toggleCamera() {
						if (!localStream) {
							console.log('本地流未初始化');
							return;
						}

						console.log('localStream---', localStream.getVideoTracks());

						// 获取视频轨道
						const videoTrack = localStream.getVideoTracks()[0];

						// 判断视频轨道是否存在
						if (videoTrack) {
							// 切换视频轨道的 enabled 属性
							videoTrack.enabled = !videoTrack.enabled;
							this.isCameraOn = videoTrack.enabled;

							// 根据摄像头的状态进行相应的处理
							if (videoTrack.enabled) {
								console.log('摄像头已开启');
							} else {
								console.log('摄像头已关闭');
							}

							// 更新远程视频流（通过设置 videoTrack.enabled 影响远程视频的接收）
							this.updateRemoteVideoTrackState(videoTrack.enabled);

							// 通知远程端摄像头状态变化
							let content = {
								call_type: this.call_type,
								isCameraOn: this.isCameraOn,
								type: 1 // 开启或关闭摄像头
							};
							var obj = {
								type: 'push',
								content: JSON.stringify(content)
							};
							this.postMessageFn(obj);
						} else {
							console.log('未找到视频轨道');
							// 如果没有视频轨道，尝试重新初始化流
							this.reinitializeStream();
						}
					},

					// 重新初始化视频流
					reinitializeStream() {
						console.log('重新初始化视频流...');
						navigator.mediaDevices.getUserMedia({
							video: true
						})
							.then(stream => {
								// 更新本地流
								localStream = stream;

								// 重新获取视频轨道
								const videoTrack = localStream.getVideoTracks()[0];
								if (videoTrack) {
									// 根据当前的摄像头状态设置视频轨道的 enabled 属性
									videoTrack.enabled = this.isCameraOn;
									console.log('重新获取并启用视频轨道');
								}
							})
							.catch(error => {
								console.error('重新获取视频流失败', error);
							});
					},



					// 更新远程视频轨道的状态
					updateRemoteVideoTrackState(isEnabled) {
						// 更新 peerConnection 的视频轨道状态
						peerConnection.getSenders().forEach(sender => {
							if (sender.track && sender.track.kind === 'video') {
								sender.track.enabled = isEnabled;
							}
						});
					},

					// 更新远程音频轨道的状态
					updateRemoteAudioTrackState(isEnabled) {
						// 更新 peerConnection 的音频轨道状态
						peerConnection.getSenders().forEach(sender => {
							if (sender.track && sender.track.kind === 'audio') {
								sender.track.enabled = isEnabled;
							}
						});
					},
					// 初始化数据
					RTCPeerConnectionFn() {
						return new Promise((resolve, reject) => {
							this.initializeCamera(null, () => {
								resolve();

							})


							// 监听 ICE 候选事件
							peerConnection.onicecandidate = event => {
								if (event.candidate) {
									var candidate = event.candidate;
									var wantHostMode = false;
									var wantReflexiveMode = false;
									var wantRelayMode = true; //此时此刻我们只想要后台中转模式
									var isHost = (candidate.candidate.indexOf(
										'typ host') !== -1);
									var isSrflx = (candidate.candidate.indexOf(
										'srflx') !== -1);
									var isRelay = (candidate.candidate.indexOf(
										'relay') !== -1);
									var candidateType = isHost ? 'host' : (isSrflx ?
										'srflx' : 'relay');

									//host（局域网直连）、srflx（打洞直连）、relay（服务器中转）
									if (wantHostMode && candidate.candidate.indexOf(
										'typ host') == -1)
										return;

									if (wantReflexiveMode && candidate.candidate
										.indexOf('srflx') == -1)
										return;

									if (wantRelayMode && candidate.candidate.indexOf(
										'relay') == -1)
										return;

									console.log("构建ICE包", candidate.candidate);
									//console.log("candidateType:" + candidateType);


									var obj = {
										cmd: "webrtc",
										user_id: this.friendInfo.id,
										type: 'ice-candidate',
										candidate: JSON.stringify(candidate)
									};
									if (faqifang) {
										sendIceArr.push(obj);
										console.log("我是发起方添加sendIceArr包", sendIceArr);

									} else {
										this.postMessageFn(obj)
										console.log("我不是发起方，发送relay服务中转", obj);

									}

								}
							};


							// 监听 ICE 连接状态变化
							peerConnection.oniceconnectionstatechange = () => {
								console.log('ICE Connection State Change:',
									peerConnection.iceConnectionState);
								if (peerConnection.iceConnectionState ===
									'disconnected' || peerConnection
										.iceConnectionState === 'failed') {
									console.log('对方已断开连接');
									this.hangUp()
									// 你可以在这里做一些断开连接后的处理，例如更新 UI，提示用户等
								}
							};

							// 监听远端媒体流
							peerConnection.ontrack = (event) => {
								console.log('接收到远端媒体流，开始了', event.streams[0]);
								document.getElementById('remoteVideo').srcObject =
									event.streams[0];

								// 如果远端流被停止，说明对方可能已经断开连接
								event.streams[0].getTracks().forEach(track => {
									track.onended = () => {
										console.log('远端流已停止，可能对方已断开');
										// 对方已断开，做一些清理操作或提示
										this.hangUp()

									};
								});
							};

							// 监听 ICE 候选状态
							peerConnection.onicegatheringstatechange = () => {
								console.log('ICE gathering state: ', peerConnection
									.iceGatheringState);
								if (peerConnection.iceGatheringState === 'complete') {
									console.log('ICE gathering complete');
								}
							};



						});
					},



					// 传递数据到父级
					postMessageFn(obj) {
						if (isH5) {
							window.parent.postMessage(obj, '*');
						} else {
							uni.postMessage({
								data: obj
							});
						}
					},
					startCall() {
						if (this.timer) {
							clearInterval(this.timer);
						}
						if (this.callTimer) {
							clearInterval(this.callTimer);
						}
						if (this.callTimer2) {
							clearTimeout(this.callTimer2)
						}
						this.callDuration = 0;
						this.timer = setInterval(() => {
							this.callDuration += 1;
						}, 1000);
					},
					endCall() {
						if (this.callTimer) {
							clearInterval(this.callTimer);
						}
						if (this.callTimer2) {
							clearTimeout(this.callTimer2)
						}
						if (this.timer) {
							clearInterval(this.timer);
							this.timer = null;
						}
					},

				}
			});
		});
	});
</script>

</html>